<!--
    @Title: IfcTiler
    @Author  dudalei
    @Package
    @Date  2024/12/5 13:37
    @description:
-->
<script setup lang="ts">
import { onMounted, ref, useTemplateRef } from 'vue'
import {
  Components,
  Grids,
  IfcPropertiesUtils,
  IfcRelationsIndexer,
  SimpleCamera,
  SimpleRenderer,
  SimpleScene,
  Worlds,
} from '@thatopen/components'
import { Highlighter, IfcStreamer } from '@thatopen/components-front'

import Stats from 'stats.js'
import { BoxGeometry, Mesh, MeshLambertMaterial } from 'three'

const container = useTemplateRef<HTMLHtmlElement>('containerRef')

const components = new Components()

const worlds = components.get(Worlds)

const world = worlds.create<SimpleScene, SimpleCamera, SimpleRenderer>()

/**
 *初始化场景
 */
function init() {
  if (!container.value) {
    return
  }

  world.scene = new SimpleScene(components)
  world.renderer = new SimpleRenderer(components, container.value)
  world.camera = new SimpleCamera(components)

  components.init()

  world.scene.setup()

  world.scene.three.background = null

  // 添加threejs的立方体案列
  // const material = new MeshLambertMaterial({ color: '#6528D7' })
  // const geometry = new BoxGeometry()
  // const cube = new Mesh(geometry, material)
  // world.scene.three.add(cube)

  world.camera.controls.setLookAt(12, 6, 8, 0, 0, -10)

  console.log('world.camera', world.camera)

  // 添加fps 统计
  const stats = new Stats()
  stats.showPanel(0)
  container.value.append(stats.dom)
  stats.dom.style.left = '0px'
  stats.dom.style.zIndex = 'unset'
  world.renderer.onBeforeUpdate.add(() => stats.begin())
  world.renderer.onAfterUpdate.add(() => stats.end())

  // 添加网格布局
  const grids = components.get(Grids)
  grids.create(world)
  world.camera.controls.addEventListener('sleep', () => {
    loader.culler.needsUpdate = true
  })
  initHighlighter()
  initIfcStreamer()
}
let loader: IfcStreamer
async function initIfcStreamer() {
  loader = components.get(IfcStreamer)
  loader.world = world
  loader.url = 'http://localhost:8081/ifcTiler/'
  loader.useCache = true

  // 一共12个模型
  for (let i = 1; i < 13; i++) {
    await loadModel(
      `http://localhost:8081/ifcTiler/all-${i}.ifc-processed.json`,
      `http://localhost:8081/ifcTiler/all-${i}.ifc-processed-properties.json`,
      // "https://thatopen.github.io/engine_components/resources/streaming/small.ifc-processed-properties.json",
    )
  }
}
// 存放加载的模型
const modelList = new Set<any>()

/**
 * 加载模型
 * @param geometryURL 模型链接
 * @param propertiesURL 属性链接
 */
async function loadModel(geometryURL: string, propertiesURL?: string) {
  const rawGeometryData = await fetch(geometryURL)
  const geometryData = await rawGeometryData.json()
  // 加载模型的属性
  let propertiesData
  if (propertiesURL) {
    const rawPropertiesData = await fetch(propertiesURL)
    propertiesData = await rawPropertiesData.json()
  }

  const model = await loader.load(geometryData, true, propertiesData)
  modelList.add(model)
  // 把模型变小
  // model.scale.set(0.1, 0.1, 0.1)
  // 如果有属性则进行选择
  if (propertiesData) {
    await select(model)
  }
  // console.log(model)
  console.log('模型加载完成', geometryURL)
}

let highlighter: Highlighter
let indexer: IfcRelationsIndexer
// 折叠面板选择的名字
const collapseNames = ref<string[]>([])
// 属性数据
const propertySets = ref<{ title: string; data: { title: string; value: string }[] }[]>([])
function initHighlighter() {
  highlighter = components.get(Highlighter)
  highlighter.setup({ world })
  // 选择模型后可以自动缩放到选择区域
  highlighter.zoomToSelection = true
  // 一旦模型加载到内存中，你只需要获取 IfcRelationsIndexer 的实例并处理模型......就这么简单！😎

  indexer = components.get(IfcRelationsIndexer)
  highlighter.events.select.onClear.add(() => {
    console.log('clear')
    collapseNames.value = []
    propertySets.value = []
  })

  highlighter.events.select.onHighlight.add((fragmentIdMap) => {
    Object.values(fragmentIdMap).forEach(async (item: Set<number>, index) => {
      if (index > 0) {
        return
      }

      let selectId: number
      for (const id of item) {
        selectId = id
        if (selectId != null) {
          continue
        }
      }

      modelList.values().find(async (model) => {
        const psets = indexer.getEntityRelations(model, selectId, 'IsDefinedBy')
        if (!psets) {
          return false
        }
        for (const expressID of psets) {
          // You can get the pset attributes like this
          const pset = await model.getProperties(expressID)
          collapseNames.value.push(pset.Name.value)
          const data = []
          propertySets.value.push({ title: pset.Name.value, data: data })
          console.log('pset', pset)
          // You can get the pset props like this or iterate over pset.HasProperties yourself
          await IfcPropertiesUtils.getPsetProps(model, expressID, async (propExpressID) => {
            const prop = await model.getProperties(propExpressID)
            console.log('prop', prop)
            data.push({
              title: prop.Name.value,
              value: prop.NominalValue,
            })
          })
        }
        return true
      })
    })
  })
}

async function select(model: any) {
  await indexer.process(model)
  /*
  highlighter.events.select.onHighlight.add((fragmentIdMap) => {
    Object.values(fragmentIdMap).forEach(async (item: Set<number>, index) => {
      if (index > 0) {
        return
      }
      for (const id of item) {
        const psets = indexer.getEntityRelations(model, id, 'IsDefinedBy')
        if (psets) {
          for (const expressID of psets) {
            // You can get the pset attributes like this
            const pset = await model.getProperties(expressID)
            console.log('pset', pset)
            // You can get the pset props like this or iterate over pset.HasProperties yourself
            await IfcPropertiesUtils.getPsetProps(model, expressID, async (propExpressID) => {
              const prop = await model.getProperties(propExpressID)
              console.log('prop', prop)
            })
          }
        }
      }
    })
  })*/
}

onMounted(init)
</script>

<template>
  <div ref="containerRef" class="container"></div>
  <div class="property-sets">
    <el-collapse v-model="collapseNames">
      <el-collapse-item
        v-for="item in propertySets"
        :title="item.title"
        :name="item.title"
        :key="item.title"
      >
        <el-descriptions class="margin-top" :column="1" size="small" border>
          <el-descriptions-item v-for="(data, index) in item.data" :key="index">
            <template #label>
              {{ data.title }}
            </template>
            {{ data.value }}
          </el-descriptions-item>
        </el-descriptions>
      </el-collapse-item>
    </el-collapse>
  </div>
</template>

<style scoped>
.container {
  width: 100vw;
  height: 100vh;
}
.property-sets {
  position: absolute;
  z-index: 2;
  top: 0;
  right: 0;
  width: 300px;
  height: 100%;
  overflow: auto;
  background-color: #2f2f2f;

  :deep(.el-descriptions__body) {
    overflow: auto;
  }
}
</style>
